#ifndef CTL_HASHTABLE_DECL_H_
#define CTL_HASHTABLE_DECL_H_

#ifndef CTL_HASH_MININAL_CAPACITY
#define CTL_HASH_MININAL_CAPACITY 4U
#endif
#ifndef CTL_HASH_GROW_FACTOR
#define CTL_HASH_GROW_FACTOR 2U
#endif
#ifndef CTL_HASH_SHRINK_RATIO
#define CTL_HASH_SHRINK_RATIO 0.5
#endif


#define DECL_HASHSET(TYPE, HASH, EQ) \
typedef struct _ctl_hashset_##TYPE##_##HASH##_##EQ##_node { \
  struct _ctl_hashset_##TYPE##_##HASH##_##EQ##_node* next; \
  TYPE value; \
} ctl_hashset_##TYPE##_##HASH##_##EQ##_node; \
typedef struct { \
  size_t bucket_size; \
  size_t size; \
  ctl_hashset_##TYPE##_##HASH##_##EQ##_node** buckets; \
} ctl_hashset_##TYPE##_##HASH##_##EQ; \
typedef struct { \
  size_t bucket_idx; \
  size_t bucket_size; \
  ctl_hashset_##TYPE##_##HASH##_##EQ##_node** buckets; \
  ctl_hashset_##TYPE##_##HASH##_##EQ##_node* node; \
} ctl_hashset_##TYPE##_##HASH##_##EQ##_iter; \
DECL_RES(ctl_hashset_##TYPE##_##HASH##_##EQ##_iter) \
DECL_RES_P(ctl_hashset_##TYPE##_##HASH##_##EQ) \
ctl_res_##TYPE ctl_hashset_##TYPE##_##HASH##_##EQ##_iter_data(ctl_hashset_##TYPE##_##HASH##_##EQ##_iter iter); \
ctl_res_ctl_hashset_##TYPE##_##HASH##_##EQ##_iter ctl_hashset_##TYPE##_##HASH##_##EQ##_iter_next(ctl_hashset_##TYPE##_##HASH##_##EQ##_iter iter); \
ctl_res_ctl_hashset_##TYPE##_##HASH##_##EQ##_iter ctl_hashset_##TYPE##_##HASH##_##EQ##_begin(ctl_hashset_##TYPE##_##HASH##_##EQ* ht); \
size_t ctl_hashset_##TYPE##_##HASH##_##EQ##_size(ctl_hashset_##TYPE##_##HASH##_##EQ* ht); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_ctor_with_capacity(ctl_hashset_##TYPE##_##HASH##_##EQ* ht, size_t capacity); \
ctl_res_ctl_hashset_##TYPE##_##HASH##_##EQ##_p ctl_hashset_##TYPE##_##HASH##_##EQ##_new_with_capacity(size_t capacity); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_ctor(ctl_hashset_##TYPE##_##HASH##_##EQ* ht); \
ctl_res_ctl_hashset_##TYPE##_##HASH##_##EQ##_p ctl_hashset_##TYPE##_##HASH##_##EQ##_new(); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_dtor(ctl_hashset_##TYPE##_##HASH##_##EQ* ht); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_free(ctl_hashset_##TYPE##_##HASH##_##EQ* ht); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_copy(ctl_hashset_##TYPE##_##HASH##_##EQ* dst, ctl_hashset_##TYPE##_##HASH##_##EQ* src); \
ctl_res_ctl_hashset_##TYPE##_##HASH##_##EQ##_iter ctl_hashset_##TYPE##_##HASH##_##EQ##_get(const ctl_hashset_##TYPE##_##HASH##_##EQ* ht, TYPE value); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_put(ctl_hashset_##TYPE##_##HASH##_##EQ* ht, TYPE value); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_remove_by_iter(ctl_hashset_##TYPE##_##HASH##_##EQ* ht, ctl_hashset_##TYPE##_##HASH##_##EQ##_iter iter); \
ctl_res_void ctl_hashset_##TYPE##_##HASH##_##EQ##_remove(ctl_hashset_##TYPE##_##HASH##_##EQ* ht, TYPE value); \


#endif